package org.unidata.mdm.search.dto;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.unidata.mdm.search.context.ComplexSearchRequestContext;
import org.unidata.mdm.search.context.ComplexSearchRequestContext.ComplexSearchRequestType;
import org.unidata.mdm.search.type.IndexType;

/**
 * @author Mikhail Mikhailov on Mar 5, 2020
 */
public class ComplexSearchResultDTO implements SearchOutputContainer {

    private final List<SearchResultDTO> supplementary;

    private final SearchResultDTO main;

    private final ComplexSearchRequestContext.ComplexSearchRequestType complexSearchType;
    /**
     * Constructor.
     * @param results a set of equally important results
     */
    public ComplexSearchResultDTO(Collection<SearchResultDTO> results) {
        super();
        this.main = null;
        this.supplementary = CollectionUtils.isEmpty(results) ? null : new ArrayList<>(results);
        this.complexSearchType = ComplexSearchRequestType.MULTI;
    }
    /**
     * Constructor.
     * @param main the main result
     * @param results the supplementary results
     */
    public ComplexSearchResultDTO(SearchResultDTO main, Collection<SearchResultDTO> results) {
        super();
        this.main = main;
        this.supplementary = CollectionUtils.isEmpty(results) ? null : new ArrayList<>(results);
        this.complexSearchType = ComplexSearchRequestType.HIERARCHICAL;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public SearchOutputContainerType getContainerType() {
        return SearchOutputContainerType.COMPLEX;
    }
    /**
     * @return the main results set
     */
    public SearchResultDTO getMain() {
        return main;
    }
    /**
     * @return the supplementary results
     */
    public List<SearchResultDTO> getSupplementary() {
        return Objects.isNull(supplementary) ? Collections.emptyList() : supplementary;
    }
    /**
     * Tells, whether this container holds results for specific index type.
     * @param type the index type
     * @return true, if it holds results for the given type, false otherwise
     */
    public boolean hasResultsFor(IndexType type) {

        if (Objects.isNull(type)) {
            return false;
        }

        if (getComplexSearchType() == ComplexSearchRequestType.HIERARCHICAL
         && main != null
         && main.getIndexType() == type) {
            return true;
        }

        return getSupplementary().stream().anyMatch(r -> type.equals(r.getIndexType()));
    }
    /**
     * Tells, whether this container holds results for specific index type.
     * @param type the index type
     * @return true, if it holds results for the given type, false otherwise
     */
    public boolean hasResultsFor(IndexType... types) {

        if (ArrayUtils.isEmpty(types)) {
            return false;
        }

        Stream<IndexType> s = Arrays.stream(types);
        if (getComplexSearchType() == ComplexSearchRequestType.HIERARCHICAL
         && main != null
         && s.anyMatch(t -> main.getIndexType() == t)) {
            return true;
        }

        return getSupplementary().stream().anyMatch(result -> s.anyMatch(t -> t == result.getIndexType()));
    }

    /**
     * @return the complexSearchType
     */
    public ComplexSearchRequestContext.ComplexSearchRequestType getComplexSearchType() {
        return complexSearchType;
    }
}
